import { Injectable } from '@nestjs/common';

/**
 * JSON工具类
 * 基于 NestJS 实现 Java 风格的 JacksonUtils
 * 对应 Java: JacksonUtils
 */
@Injectable()
export class JsonUtil {
  /**
   * 将对象转换为JSON字符串
   * @param obj 要转换的对象
   * @param pretty 是否格式化输出
   * @returns JSON字符串
   */
  toJsonString(obj: any, pretty: boolean = false): string {
    try {
      if (pretty) {
        return JSON.stringify(obj, null, 2);
      }
      return JSON.stringify(obj);
    } catch (error) {
      throw new Error(
        `Failed to convert object to JSON string: ${error.message}`,
      );
    }
  }

  /**
   * 将JSON字符串转换为对象
   * @param jsonString JSON字符串
   * @param targetClass 目标类（可选）
   * @returns 转换后的对象
   */
  fromJsonString<T = any>(
    jsonString: string,
    targetClass?: new (...args: any[]) => T,
  ): T | null {
    try {
      const obj = JSON.parse(jsonString);
      if (targetClass) {
        return this.toObject(obj, targetClass);
      }
      return obj;
    } catch (error) {
      throw new Error(
        `Failed to convert JSON string to object: ${error.message}`,
      );
    }
  }

  /**
   * 将对象转换为指定类型的对象
   * @param obj 源对象
   * @param targetClass 目标类
   * @returns 转换后的对象
   */
  toObject<T = any>(
    obj: any,
    targetClass: new (...args: any[]) => T,
  ): T | null {
    if (!obj || !targetClass) {
      return null;
    }

    try {
      const target = new targetClass();
      this.copyProperties(obj, target);
      return target;
    } catch (error) {
      throw new Error(
        `Failed to convert object to target class: ${error.message}`,
      );
    }
  }

  /**
   * 将对象列表转换为指定类型的对象列表
   * @param objList 源对象列表
   * @param targetClass 目标类
   * @returns 转换后的对象列表
   */
  toObjectList<T = any>(
    objList: any[],
    targetClass: new (...args: any[]) => T,
  ): T[] {
    if (!objList || !Array.isArray(objList)) {
      return [];
    }

    const result: T[] = [];
    for (const obj of objList) {
      try {
        const target = this.toObject(obj, targetClass);
        if (target) {
          result.push(target);
        }
      } catch (error) {
        console.warn(
          `Failed to convert object to target class: ${error.message}`,
        );
      }
    }
    return result;
  }

  /**
   * 复制对象属性
   * @param source 源对象
   * @param target 目标对象
   */
  private copyProperties(source: any, target: any): void {
    if (
      !source ||
      !target ||
      typeof source !== 'object' ||
      typeof target !== 'object'
    ) {
      return;
    }

    for (const key in source) {
      if (source.hasOwnProperty(key) && target.hasOwnProperty(key)) {
        target[key] = source[key];
      }
    }
  }

  /**
   * 将对象转换为下划线命名的JSON字符串
   * @param obj 要转换的对象
   * @param pretty 是否格式化输出
   * @returns 下划线命名的JSON字符串
   */
  toSnakeCaseJsonString(obj: any, pretty: boolean = false): string {
    try {
      const snakeCaseObj = this.toSnakeCase(obj);
      return this.toJsonString(snakeCaseObj, pretty);
    } catch (error) {
      throw new Error(
        `Failed to convert object to snake case JSON string: ${error.message}`,
      );
    }
  }

  /**
   * 将下划线命名的JSON字符串转换为对象
   * @param jsonString 下划线命名的JSON字符串
   * @param targetClass 目标类（可选）
   * @returns 转换后的对象
   */
  fromSnakeCaseJsonString<T = any>(
    jsonString: string,
    targetClass?: new (...args: any[]) => T,
  ): T | null {
    try {
      const obj = JSON.parse(jsonString);
      const camelCaseObj = this.toCamelCase(obj);
      if (targetClass) {
        return this.toObject(camelCaseObj, targetClass);
      }
      return camelCaseObj;
    } catch (error) {
      throw new Error(
        `Failed to convert snake case JSON string to object: ${error.message}`,
      );
    }
  }

  /**
   * 将对象转换为下划线命名格式
   * @param obj 要转换的对象
   * @returns 下划线命名格式的对象
   */
  toSnakeCase(obj: any): any {
    if (obj === null || obj === undefined) {
      return obj;
    }

    if (Array.isArray(obj)) {
      return obj.map((item) => this.toSnakeCase(item));
    }

    if (typeof obj === 'object') {
      const result: any = {};
      for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
          const snakeKey = this.camelToSnake(key);
          result[snakeKey] = this.toSnakeCase(obj[key]);
        }
      }
      return result;
    }

    return obj;
  }

  /**
   * 将对象转换为驼峰命名格式
   * @param obj 要转换的对象
   * @returns 驼峰命名格式的对象
   */
  toCamelCase(obj: any): any {
    if (obj === null || obj === undefined) {
      return obj;
    }

    if (Array.isArray(obj)) {
      return obj.map((item) => this.toCamelCase(item));
    }

    if (typeof obj === 'object') {
      const result: any = {};
      for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
          const camelKey = this.snakeToCamel(key);
          result[camelKey] = this.toCamelCase(obj[key]);
        }
      }
      return result;
    }

    return obj;
  }

  /**
   * 驼峰转下划线
   * @param str 驼峰字符串
   * @returns 下划线字符串
   */
  private camelToSnake(str: string): string {
    return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
  }

  /**
   * 下划线转驼峰
   * @param str 下划线字符串
   * @returns 驼峰字符串
   */
  private snakeToCamel(str: string): string {
    return str.replace(/_([a-z])/g, (match, letter) => letter.toUpperCase());
  }

  /**
   * 检查字符串是否为有效的JSON
   * @param str 要检查的字符串
   * @returns 是否为有效的JSON
   */
  isValidJson(str: string): boolean {
    try {
      JSON.parse(str);
      return true;
    } catch (error) {
      return false;
    }
  }

  /**
   * 安全地将JSON字符串转换为对象
   * @param jsonString JSON字符串
   * @param defaultValue 默认值
   * @returns 转换后的对象或默认值
   */
  safeFromJsonString<T = any>(jsonString: string, defaultValue: T): T {
    try {
      return JSON.parse(jsonString);
    } catch (error) {
      return defaultValue;
    }
  }

  /**
   * 合并JSON对象
   * @param target 目标对象
   * @param sources 源对象数组
   * @returns 合并后的对象
   */
  mergeJson<T = any>(target: T, ...sources: any[]): T {
    if (!target) {
      target = {} as T;
    }

    for (const source of sources) {
      if (source && typeof source === 'object') {
        this.deepMerge(target, source);
      }
    }

    return target;
  }

  /**
   * 深度合并对象
   * @param target 目标对象
   * @param source 源对象
   */
  private deepMerge(target: any, source: any): void {
    for (const key in source) {
      if (source.hasOwnProperty(key)) {
        const sourceValue = source[key];
        const targetValue = target[key];

        if (this.isObject(sourceValue) && this.isObject(targetValue)) {
          this.deepMerge(targetValue, sourceValue);
        } else {
          target[key] = JSON.parse(JSON.stringify(sourceValue));
        }
      }
    }
  }

  /**
   * 检查是否为对象
   * @param obj 要检查的值
   * @returns 是否为对象
   */
  private isObject(obj: any): boolean {
    return obj !== null && typeof obj === 'object' && !Array.isArray(obj);
  }

  /**
   * 获取JSON对象的路径值
   * @param obj JSON对象
   * @param path 路径，支持点号分隔
   * @param defaultValue 默认值
   * @returns 路径值
   */
  getPathValue<T = any>(
    obj: any,
    path: string,
    defaultValue?: T,
  ): T | undefined {
    if (!obj || !path) {
      return defaultValue;
    }

    try {
      const keys = path.split('.');
      let current = obj;

      for (const key of keys) {
        if (current === null || current === undefined) {
          return defaultValue;
        }
        current = current[key];
      }

      return current !== undefined ? current : defaultValue;
    } catch (error) {
      return defaultValue;
    }
  }

  /**
   * 设置JSON对象的路径值
   * @param obj JSON对象
   * @param path 路径，支持点号分隔
   * @param value 值
   */
  setPathValue(obj: any, path: string, value: any): void {
    if (!obj || !path) {
      return;
    }

    try {
      const keys = path.split('.');
      const lastKey = keys.pop();
      let current = obj;

      for (const key of keys) {
        if (current[key] === null || current[key] === undefined) {
          current[key] = {};
        }
        current = current[key];
      }

      if (lastKey) {
        current[lastKey] = value;
      }
    } catch (error) {
      throw new Error(`Failed to set path value ${path}: ${error.message}`);
    }
  }

  /**
   * 删除JSON对象的路径值
   * @param obj JSON对象
   * @param path 路径，支持点号分隔
   */
  deletePathValue(obj: any, path: string): void {
    if (!obj || !path) {
      return;
    }

    try {
      const keys = path.split('.');
      const lastKey = keys.pop();
      let current = obj;

      for (const key of keys) {
        if (current[key] === null || current[key] === undefined) {
          return;
        }
        current = current[key];
      }

      if (lastKey && current.hasOwnProperty(lastKey)) {
        delete current[lastKey];
      }
    } catch (error) {
      throw new Error(`Failed to delete path value ${path}: ${error.message}`);
    }
  }

  /**
   * 过滤JSON对象
   * @param obj JSON对象
   * @param predicate 过滤条件函数
   * @returns 过滤后的对象
   */
  filterJson(obj: any, predicate: (key: string, value: any) => boolean): any {
    if (!obj || typeof obj !== 'object') {
      return {};
    }

    const filtered: any = {};
    for (const key in obj) {
      if (obj.hasOwnProperty(key) && predicate(key, obj[key])) {
        filtered[key] = obj[key];
      }
    }

    return filtered;
  }

  /**
   * 映射JSON对象
   * @param obj JSON对象
   * @param mapper 映射函数
   * @returns 映射后的对象
   */
  mapJson(obj: any, mapper: (key: string, value: any) => any): any {
    if (!obj || typeof obj !== 'object') {
      return {};
    }

    const mapped: any = {};
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        mapped[key] = mapper(key, obj[key]);
      }
    }

    return mapped;
  }
}
